package com.cyj.dream.middleware.hystrix.aspect;

import com.cyj.dream.middleware.hystrix.annotation.DoHystrix;
import com.cyj.dream.middleware.hystrix.value.IValveService;
import com.cyj.dream.middleware.hystrix.value.impl.HystrixValveImpl;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @Description: 熔断切面逻辑实现--自定义切面的实现比较简单，只是拦截方法和处理相应的操作。
 * @BelongsProject: DreamChardonnayCloud
 * @BelongsPackage: com.cyj.dream.middleware.hystrix.aspect
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-15 20:22
 * @Email: chen87647213@163.com
 * @Version: 1.0
 */
@Aspect
@Component
public class DoHystrixPoint {

    /**
     * 配置切点
     *
     * @return void
     * @date 2021/9/15 20:23
     * @author ChenYongJia
     * @version 1.0
     */
    @Pointcut("@annotation(com.cyj.dream.middleware.hystrix.annotation.DoHystrix)")
    public void aopPoint() {
    }

    /**
     * 1. @Around("aopPoint() && @annotation(doGovern)") ，这块的处理是本章节新增的，一般在方法入参中并没有直接提供自定义注解的获取，
     * 直接通过方法入参的方式可以更加方便的拿到注解，处理起来也更优雅。这种是怎么实现的呢？ 那个doGovern相当于参数名？和impl类中的命令组什么的无关吧？
     * https://codechina.csdn.net/MiddlewareDesign/hystrix-spring-boot-starter/-/issues/2
     *
     * @param jp
     * @param doGovern
     * @return java.lang.Object
     * @date 2021/9/15 20:26
     * @author ChenYongJia
     * @version 1.0
     */
    @Around("aopPoint() && @annotation(doGovern)")
    public Object doRouter(ProceedingJoinPoint jp, DoHystrix doGovern) throws Throwable {
        IValveService valveService = new HystrixValveImpl(doGovern.timeoutValue());
        // 方法内容的调用逻辑，valveService.access(jp, getMethod(jp), doGovern, jp.getArgs()); ，这步调用的就是我们包装好的熔断保护服务。
        return valveService.access(jp, getMethod(jp), doGovern, jp.getArgs());
    }

    private Method getMethod(JoinPoint jp) throws NoSuchMethodException {
        Signature sig = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) sig;
        return jp.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
    }

}

